package com.qf.smsplatform.interfaces.mq;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.smsplatform.common.constants.CacheConstants;
import com.qf.smsplatform.common.constants.RabbitMQConstants;
import com.qf.smsplatform.common.model.StandardReport;
import com.qf.smsplatform.interfaces.client.CacheClient;
import com.qf.smsplatform.interfaces.config.RabbitMQConfig;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 * 监听状态报告推送的消费者
 * @author zjw
 */
@Component
@Slf4j
public class PushReportListener {

    private int[] sendTimeInterval = {0,5000,10000,30000,60000};

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private CacheClient cacheClient;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final String SUCCESS = "SUCCESS";

    /**
     * 第一次推送
     * @param report
     * @param channel
     * @param message
     * @throws Exception
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void consume(StandardReport report, Channel channel, Message message) throws Exception {
        //1. 查询当前客户接收状态报告的地址
        String receiveStatusUrl = cacheClient.hget(CacheConstants.CACHE_PREFIX_CLIENT + report.getClientID(), "receivestatusurl");
        report.setReceiveStatusUrl(receiveStatusUrl);
        //2. 发送请求到客户。返回flag
        boolean flag = sendReport(report, receiveStatusUrl);

        sendDelayedMessage(report, flag);
        // 手动ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    /**
     * 第2次到第5次的重试
     * @param report
     * @param channel
     * @param message
     * @throws Exception
     */
    @RabbitListener(queues = RabbitMQConfig.DELAYED_QUEUE)
    public void delayedConsume(StandardReport report, Channel channel, Message message) throws Exception {
        //1. 获取路径，已经设置发送次数+1
        String receiveStatusUrl = report.getReceiveStatusUrl();

        //2. 发送请求
        boolean flag = sendReport(report, receiveStatusUrl);

        //3. 判断是否成功
        sendDelayedMessage(report, flag);

        //4. 手动ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    private void sendDelayedMessage(StandardReport report, boolean flag) {
        if(report.getSendCount() >= 5){
            log.info("【接口模块-推送状态报告】 第{}次推送状态报告失败！！不再重新推送！！",report.getSendCount());
            return;
        }
        //2. 根据flag判断发送是否成功
        if (flag) {
            // 推送失败
            log.info("【接口模块-推送状态报告】  第{}次推送状态报告失败！！ report = {}", report.getSendCount(), report);
            //7. 发一个消息到延迟交换机，并设置生存时间5s，如果第二次10s………………
            rabbitTemplate.convertAndSend(RabbitMQConfig.DELAYED_EXCHANGE, RabbitMQConfig.DELAYED_QUEUE, report, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    MessageProperties messageProperties = message.getMessageProperties();
                    messageProperties.setDelay(sendTimeInterval[report.getSendCount()]);
                    return message;
                }
            });
        }
    }

    private boolean sendReport(StandardReport report, String receiveStatusUrl) throws JsonProcessingException {
        report.setSendCount(report.getSendCount() + 1);

        //2. 需要向上述查询的路径发送请求，并且将report序列化为JSON，作为参数
        String requestParameter = objectMapper.writeValueAsString(report);

        //3. 声明请求头信息
        HttpHeaders requestHeader = new HttpHeaders();
        requestHeader.setContentType(MediaType.APPLICATION_JSON_UTF8);

        boolean flag = false;
        //4. 使用RestTemplate发送POST请求到客户地址
        try {
            log.info("【接口模块-推送状态报告】  第{}次推送状态报告!!!! report = {}", report.getSendCount(), report);
            String result = restTemplate.postForObject(receiveStatusUrl, new HttpEntity<>(requestParameter, requestHeader), String.class);
            if (!SUCCESS.equals(result)) {
                // 请求失败，返回的不是SUCCESS
                flag = true;
            }
            //6. 针对发送请求的结果做判断，如果不是SUCCESS，说明通知失败
        } catch (RestClientException e) {
            //5. 针对发送请求做try-catch处理，如果到catch，说明通知失败
            flag = true;
        }
        return flag;
    }
}
